package com.dragon.modules.yuegou.client.wechat_mini.service.impl;

import com.dragon.modules.yuegou.client.wechat_mini.client.MiniClient;
import com.dragon.modules.yuegou.client.wechat_mini.client.impl.MiniClientImpl;
import com.dragon.modules.yuegou.client.wechat_mini.common.MiniConfig;
import com.dragon.modules.yuegou.client.wechat_mini.common.MiniException;
import com.dragon.modules.yuegou.client.wechat_mini.request.TemplateAddRequest;
import com.dragon.modules.yuegou.client.wechat_mini.security.AccessTokenRepository;
import com.dragon.modules.yuegou.client.wechat_mini.security.AccessTokenService;
import com.dragon.modules.yuegou.client.wechat_mini.security.DefaultAccessTokenRepository;
import com.dragon.modules.yuegou.client.wechat_mini.security.DefaultMiniRegistry;
import com.dragon.modules.yuegou.client.wechat_mini.security.MiniRegistry;
import com.dragon.modules.yuegou.client.wechat_mini.security.impl.AccessTokenServiceImpl;
import com.dragon.modules.yuegou.client.wechat_mini.service.AuthService;
import com.dragon.modules.yuegou.client.wechat_mini.service.MiniMultiService;
import com.dragon.modules.yuegou.client.wechat_mini.service.SecurityService;
import com.dragon.modules.yuegou.client.wechat_mini.service.SubscribeMessageService;
import com.dragon.modules.yuegou.client.wechat_mini.service.WxaCodeService;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 小程序服务（多小程序版）实现
 * 
 * @author liuwu
 *
 */
public class MiniMultiServiceImpl implements MiniMultiService {

	/**
	 * 小程序接口客户端
	 */
	private final MiniClient client;

	/**
	 * 小程序注册中心
	 */
	private final MiniRegistry registry;

	/**
	 * 接口凭证仓库
	 */
	private final AccessTokenRepository accessTokenRepository;

	/**
	 * 构造一个小程序服务（多小程序版）
	 * 
	 * @param configs 小程序配置映射表，name为小程序唯一标识（可以自定义也可以使用appid），value为小程序账号信息
	 */
	public MiniMultiServiceImpl(Map<String, MiniConfig> configs) {
		this(new DefaultMiniRegistry(configs), new MiniClientImpl(), new DefaultAccessTokenRepository());
	}
	
	/**
	 * 构造一个小程序服务（多小程序版）
	 * 
	 * @param registry 小程序注册中心
	 */
	public MiniMultiServiceImpl(MiniRegistry registry) {
		this(registry, new MiniClientImpl(), new DefaultAccessTokenRepository());
	}

	/**
	 * 构造一个小程序服务（多小程序版）
	 * 
	 * @param registry 小程序注册中心
	 * @param client   小程序客户端
	 */
	public MiniMultiServiceImpl(MiniRegistry registry, MiniClient client) {
		this(registry, client, new DefaultAccessTokenRepository());
	}

	/**
	 * 构造一个小程序服务（多小程序版）
	 * 
	 * @param registry              小程序注册中心
	 * @param client                小程序客户端
	 * @param accessTokenRepository 接口凭证仓库，如需集群部署，请使用或自行实现共享数据仓库（例如CacheAccessTokenRepositoryImpl）
	 */
	public MiniMultiServiceImpl(MiniRegistry registry, MiniClient client, AccessTokenRepository accessTokenRepository) {
		super();
		this.client = client;
		this.registry = registry;
		this.accessTokenRepository = accessTokenRepository;
	}

	@Override
	public AccessTokenService tokenService(String name) {
		MiniConfig config = registry.get(name);
		if (config == null) {
			throw new MiniException("小程序账号不存在：" + name);
		}
		return new AccessTokenServiceImpl(client.auth(), accessTokenRepository, config);
	}

	@Override
	public AuthService auth(String name) {
		return new AuthServiceImpl(client.auth(), registry.get(name), tokenService(name));
	}
	
	@Override
	public WxaCodeService wxaCode(String name) {
		return new WxaCodeServiceImpl(client.wxaCode(), tokenService(name));
	}

	@Override
	public SecurityService security(String name) {
		return new SecurityServiceImpl(client.security(), tokenService(name));
	}

	/**
	 * 订阅消息服务是有状态服务，需要缓存
	 */
	private Map<String, SubscribeMessageService> subscribeMessageCache = new HashMap<>();

	@Override
	public SubscribeMessageService subscribeMessage(String name) {
		SubscribeMessageService service = subscribeMessageCache.get(name);
		if (service != null) {
			return service;
		}
		synchronized (subscribeMessageCache) {
			// double check
			service = subscribeMessageCache.get(name);
			if (service == null) {
				service = new SubscribeMessageServiceImpl(client.subscribeMessage(), tokenService(name));
				service.configTemplate(templateConfig);
				subscribeMessageCache.put(name, service);
			}
			return service;
		}
	}

	private List<TemplateAddRequest> templateConfig;

	@Override
	public void configTemplate(List<TemplateAddRequest> templateConfig) {
		this.templateConfig = templateConfig;
		synchronized (subscribeMessageCache) {
			subscribeMessageCache.values().forEach(service -> service.configTemplate(templateConfig));
		}
	}

}
